package com.cgq.controller;

import com.cgq.service.PhoneService;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * *  Author:陈国强
 * *  Description:
 * *  Date:2023/2/14 19:56
 */
@RestController
@RequestMapping("/phone")
public class PhoneController {

    @Autowired
    private PhoneService service;

    //普通synchronized锁，结果是两个tomcat服务器进行访问的时候，都会购买成功，没有效果
    @GetMapping("/buyPhone")
    public String buyPhone(Integer id){
        return service.getNumberById(id);
    }


    //JUC 包下的Lock锁
    @GetMapping("/buyPhone1")
    public String buyPhone1(Integer id){
        return service.getNumberById1(id);
    }

    // 解决分布式锁的问题   借助 setnx 咱们先手动实现一个
    @GetMapping("/buyPhone2")
    public String buyPhone2(Integer id){
        return service.getNumberById2(id);
    }


    //利用redisson分布式锁解决
    @GetMapping("/buyPhone3")
    public String buyPhone3(Integer id){
        return service.getNumberById3(id);
    }




    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;

    //**读写锁** ReadWriteLock
    // RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
    @GetMapping("/write")
    @ResponseBody
    public String writeValue(){
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("rw-lock");

        String s="";

        RLock rLock = readWriteLock.writeLock();
        try {
            // 改数据  加写锁    读数据 加 读锁
            rLock.lock();
            s = UUID.randomUUID().toString();
            TimeUnit.SECONDS.sleep(15);
            redisTemplate.opsForValue().set("writeValue",s);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            rLock.unlock();
        }

        return s;
    }

    //**读锁** ReadWriteLock
    @GetMapping("/read")
    @ResponseBody
    public String readValue() {
        RReadWriteLock readLock = redissonClient.getReadWriteLock("rw-lock");

        //读锁
        RLock rLock = readLock.readLock();
        //生命value为空
        String value = "";
        try {
            rLock.lock();  // 加 读锁

            //读取写锁的时候添加进去的锁信息get
            value = redisTemplate.opsForValue().get("writeValue");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放锁
            rLock.unlock();
        }
        //读出锁信息
        return value;
    }

    //闭锁问题演示
    /**
     * 放假 锁学校大门
     *
     * 5个班全部走完  我们可以锁大门
     * */

    //先对redis缓存中加入count的值
    @GetMapping("/lockDoor")
    @ResponseBody
    public String  lockDoor() throws InterruptedException {
        //闭锁
        RCountDownLatch door = redissonClient.getCountDownLatch("door");

        door.trySetCount(5);   // 5个班

        door.await();  //  等待闭锁都完成

        return "放假了";
    }


    @GetMapping("/gogogo/{id}")
    @ResponseBody
    public String gogogo(@PathVariable("id") Long id){

        RCountDownLatch door = redissonClient.getCountDownLatch("door");

        door.countDown();   // 计数减一

        return id+"班的人都走了";
    }


    /**
     * 车位停车
     * 3车位
     *  利用信号量的特性   可以进行   限流操作
     *  比如 系统只能供10000 个线程访问  ，就可以分配10000 个 信号量
     * */
    //基于Redis的Redisson的分布式信号量Semaphore Java对象`RSemaphore`采用了与
    @GetMapping("/park")
    @ResponseBody
    public String park() throws InterruptedException {
        //先在 redis设置键值：   set park 3
        RSemaphore park = redissonClient.getSemaphore("park");
        // park.acquire();  // 获取一个信号 获取一个值 占一个车位    可以执行三次  车位占完  就没法继续往下执行了   需要释放

        boolean b = park.tryAcquire();   // 尝试 获取信号量   获取到返回 true  获取不到  返回false
        // 限流操作
        if(b){
            // 车位够  执行业务
        }else{
            // 车位不够  执行限流
        }
        return "ok" + b;
    }

    @GetMapping("/go")
    @ResponseBody
    public String go(){
        RSemaphore park = redissonClient.getSemaphore("park");
        park.release();   // 释放一个车位
        return "现在存在空闲车位";
    }
    
}
